package com.hqd.ch03.v18.listener.support;

import com.hqd.ch03.v18.factory.BeanFactory;
import com.hqd.ch03.v18.listener.BeanFactoryEventMulticaster;
import com.hqd.ch03.v18.listener.BeanFactoryListener;
import com.hqd.ch03.v18.listener.event.BeanFactoryEvent;
import com.hqd.ch03.v18.utils.GenericClassUtils;
import org.apache.commons.collections.CollectionUtils;

import java.util.*;

/**
 * 事件广播器默认处理
 */
public class SimpleBeanFactoryEventMulticaster implements BeanFactoryEventMulticaster {
    private BeanFactory beanFactory;
    private Set<BeanFactoryListener<?>> listeners = new LinkedHashSet<>();

    public SimpleBeanFactoryEventMulticaster(BeanFactory beanFactory) {
        this.beanFactory = beanFactory;
    }

    @Override
    public void addBeanFactoryListener(BeanFactoryListener<?> listener) {
        listeners.add(listener);
    }

    @Override
    public void addBeanFactoryListenerBean(String listenerBeanName) {
        Object bean = this.beanFactory.getBean(listenerBeanName);
        if (bean != null && bean instanceof BeanFactoryListener) {
            listeners.add((BeanFactoryListener<?>) bean);
        }
    }

    @Override
    public void removeBeanFactoryListener(BeanFactoryListener<?> listener) {
        listeners.remove(listener);
    }

    @Override
    public void removeBeanFactoryListenerBean(String listenerBeanName) {
        Object bean = this.beanFactory.getBean(listenerBeanName);
        if (bean != null && bean instanceof BeanFactoryListener) {
            listeners.remove((BeanFactoryListener<?>) bean);
        }
    }

    @Override
    public void multicastEvent(BeanFactoryEvent event) {
        Collection<BeanFactoryListener> beanFactoryListeners = getBeanFactoryListeners(event);
        if (CollectionUtils.isNotEmpty(beanFactoryListeners)) {
            beanFactoryListeners.forEach(listener -> {
                listener.onEvent(event);
            });
        }
    }

    /**
     * 获取匹配的监听器
     *
     * @return
     */
    protected Collection<BeanFactoryListener> getBeanFactoryListeners(BeanFactoryEvent event) {
        if (CollectionUtils.isEmpty(this.listeners)) {
            return null;
        }
        List<BeanFactoryListener> eventListeners = new ArrayList<>(this.listeners.size());
        this.listeners.forEach(listener -> {
            Class<?> typeArgument = GenericClassUtils.getInterfaceActualTypeArgument(listener.getClass(),
                    BeanFactoryListener.class, 0);
            if (typeArgument.isAssignableFrom(event.getClass())) {
                eventListeners.add(listener);
            }
        });
        return eventListeners;
    }
}
